#pragma once
#include <functional>
#include "Socket.hpp"
#include "Log.hpp"
#include "InetAddr.hpp"
#include <unistd.h>
#include <sys/socket.h>
static const int gport=8880;
// using service_io_t=std::function<void(SockPtr,const InetAddr &)>;
class TcpServer
{
    public:
    TcpServer(uint16_t port=gport)
    :_port(port),_isRunning(false),_sock(std::make_shared<TcpSocket>())
    {
        _sock->BuildServerListenSocket(_port);
    }
    ~TcpServer()
    {
        if(_isRunning)
        {
            _sock->Close();
        }
    } 
    class ThreadData
    {
        public:
        ThreadData(SockPtr sock,TcpServer *server,const InetAddr &addr)
        :_sock(sock),_addr(addr),_server(server)
        {
        }
        public:
        SockPtr _sock;
        InetAddr _addr;
        TcpServer *_server;
    };
    void loop()
    {
        _isRunning=true;
        while(_isRunning)
        {
            InetAddr client_addr;
            SockPtr client_sock=_sock->AcceptSocket(&client_addr);
            if(client_sock==nullptr)
            {
                continue;
            }
            ThreadData *td=new ThreadData(client_sock,this,client_addr);
            pthread_t tid;
            pthread_create(&tid,nullptr,Execute,td);
            // pthread_detach(tid);
        }
        _isRunning=false;
    }
    static void *Execute(void *arg)
    {
        pthread_detach(pthread_self());//分离线程
        ThreadData *td=(ThreadData *)arg;
        td->_server->service(td->_sock,td->_addr);
        td->_sock->Close();
        delete td;
        return nullptr;
    }
    static void service(SockPtr sock, InetAddr &addr)
    {
        while (true)
        {
            char inbuffer[1024]; // 当做字符串
            ssize_t n = ::recv(sock->Sockfd(), inbuffer, sizeof(inbuffer) - 1, 0);
            if (n > 0)
            {
                inbuffer[n] = 0;
                LOG(INFO, "get message from client %s, message: %s\n", addr.AddrStr().c_str(), inbuffer);

                std::string echo_string = "[server echo] #";
                echo_string += inbuffer;
                ::send(sock->Sockfd(), echo_string.c_str(), echo_string.size(), 0);
            }
            else if (n == 0)
            {
                LOG(INFO, "client %s quit\n", addr.AddrStr().c_str());
                break;
            }
            else
            {
                LOG(ERROR, "read error from %s\n", addr.AddrStr().c_str());
                break;
            }
        }
        sock->Close();
    }

    
    private:
    SockPtr _sock;
    bool _isRunning;
    uint16_t _port;
};
